﻿/*
 * *******************************************************
 *
 * 作者：HZY
 *
 * 开源地址：https://gitee.com/hzy6
 *
 * *******************************************************
 */

namespace HZY.Framework.Core;

/// <summary>
/// 应用程序
/// </summary>
public static class App
{
    private static IServiceCollection? _serviceCollection;
    private static IHost? _host;
    private static IHttpContextAccessor? _httpContextAccessor;
    private static readonly List<IStartupModule> _startups = new();
    private static readonly List<JobTaskInfo> _jobTaskInfos = new();
    private static readonly List<string> _urls = new();
    private static WebApplication? _webApplication;
    private static WebApplicationBuilder? _webApplicationBuilder;
    private static AppOptions _appOptions = new AppOptions();

    /// <summary>
    /// IServiceCollection
    /// </summary>
    public static IServiceCollection? Services => _serviceCollection;

    /// <summary>
    /// IHost
    /// </summary>
    public static IHost? Host => _host;

    /// <summary>
    /// HttpContext
    /// </summary>
    public static HttpContext? HttpContext => _httpContextAccessor?.HttpContext;

    /// <summary>
    /// IServiceProvider
    /// </summary>
    public static IServiceProvider? ServiceProvider => _host?.Services;

    /// <summary>
    /// 程序启动器集合
    /// </summary>
    public static IStartupModule[] Startups => _startups.ToArray();

    /// <summary>
    /// 带有 ScheduledAttribute 标记的 MethodInfo 类型
    /// </summary>
    public static JobTaskInfo[] JobTaskInfos => _jobTaskInfos.ToArray();

    /// <summary>
    /// 程序启动地址
    /// </summary>
    public static string[] Urls => _urls.ToArray();

    /// <summary>
    /// WebApplication
    /// </summary>
    public static WebApplication? WebApplication => _webApplication;

    /// <summary>
    /// WebApplicationBuilder
    /// </summary>
    public static WebApplicationBuilder? WebApplicationBuilder => _webApplicationBuilder;

    /// <summary>
    /// App 配置项
    /// </summary>
    public static AppOptions AppOptions => _appOptions;

    /// <summary>
    /// 添加 hzy framework 
    /// </summary>
    /// <typeparam name="TStartupModule"></typeparam>
    /// <param name="builder"></param>
    /// <param name="options"></param>
    /// <returns></returns>
    public static WebApplicationBuilder AddHzyFramework<TStartupModule>(
        this WebApplicationBuilder builder,
        Action<AppOptions>? options = null
    )
        where TStartupModule : IStartupModule
    {
        _webApplicationBuilder = builder;
        _serviceCollection = builder.Services;

        if (Activator.CreateInstance(typeof(TStartupModule)) is IStartupModule startup)
        {
            _startups.Clear();

            var allImportStartup = startup?.GetAllImportStartup();

            var appStartupsOrderBy = allImportStartup?.OrderBy(w => w.Order).ToList();

            if (appStartupsOrderBy != null && appStartupsOrderBy.Count > 0)
            {
                _startups.AddRange(appStartupsOrderBy);
            }

            foreach (var item in _startups)
            {
                item?.ConfigureServices(builder);
            }
        }

        // 添加控制器 服务器指标监控
        builder.Services.AddSingleton<IServerMetricMonitoringService>((s) =>
            OperatingSystemUtil.IsUnix()
                ? new UnixServerMetricMonitoringService()
                : new WindowsServerMetricMonitoringService());

        options?.Invoke(_appOptions);

        // 扫描 任务计划标记 ScheduledAttribute
        if (
            _appOptions.Assemblies is null ||
            _appOptions.Assemblies.Count == 0 ||
            _appOptions.AssemblyScanScheduledSwitch
        )
        {
            _appOptions.Assemblies = AssemblyUtil.GetAssemblyList().Where(w => !w.IsDynamic).ToList();
        }

        // 扫描 任务计划标记 ScheduledAttribute
        if (_appOptions.AssemblyScanScheduledSwitch)
        {
            ScheduledAttribute.ScanScheduledAttributes(_appOptions.Assemblies, _jobTaskInfos);
        }

        // 
        _appOptions.WebApplicationBuilderAction?.Invoke(builder);

        return builder;
    }

    /// <summary>
    /// 开始启动 hzy framework 
    /// </summary>
    /// <param name="app"></param>
    /// <returns></returns>
    public static async Task StartHzyFrameworkAsync(this WebApplication app)
    {
        _webApplication = app;

        var hostApplicationLifetime = app.Services.GetService<IHostApplicationLifetime>();

        if (hostApplicationLifetime == null) return;

        // 启动
        hostApplicationLifetime.ApplicationStarted.Register(() =>
        {
            _urls.AddRange(app.Urls.ToList());

            foreach (var item in _startups)
            {
                item?.ApplicationStarted(app);
            }
        });

        // 停止中
        hostApplicationLifetime.ApplicationStopping.Register(() =>
        {
            foreach (var item in _startups)
            {
                item?.ApplicationStopping(app);
            }
        });

        // 已停止
        hostApplicationLifetime.ApplicationStopped.Register(() =>
        {
            foreach (var item in _startups)
            {
                item?.ApplicationStopped(app);
            }
        });

        _httpContextAccessor = app.Services.GetService<IHttpContextAccessor>();

        _host = app;

        // 扫描 任务计划标记 ScheduledAttribute
        ScheduledAttribute.ScanScheduledAttributes(_serviceCollection?.Select(w => w.ServiceType).ToList(),
            _jobTaskInfos);

        foreach (var item in _startups)
        {
            item?.Configure(app);
        }

        _appOptions?.WebApplicationAction?.Invoke(app);

        await app.RunAsync();
    }

    /// <summary>
    /// 创建服务域
    /// </summary>
    /// <returns></returns>
    public static IServiceScope? CreateScope() => _host?.Services?.CreateScope();

    #region 私有方法

    ///// <summary>
    ///// 查询 Startup
    ///// </summary>
    ///// <param name="assemblies"></param>
    ///// <param name="classCall"></param>
    //private static void ScanStartup(List<Assembly>? assemblies, Action<Type>? classCall)
    //{
    //    if (assemblies == null) return;

    //    _startups.Clear();

    //    foreach (var item in assemblies)
    //    {
    //        // 必须是 class 并且 不能是 泛型类
    //        var classList = item.ExportedTypes
    //            .Where(w => w.IsClass && !w.IsGenericType && w.IsPublic)
    //            ;

    //        if (classList.Count() == 0) continue;

    //        foreach (var _classType in classList.Distinct())
    //        {
    //            try
    //            {
    //                if (typeof(IStartupModule).IsAssignableFrom(_classType))
    //                {
    //                    var appStartup = Activator.CreateInstance(_classType) as IStartupModule;
    //                    if (appStartup == null) continue;
    //                    _startups.Add(appStartup);
    //                }

    //                classCall?.Invoke(_classType);

    //            }
    //            catch (Exception)
    //            {
    //                continue;
    //            }
    //        }
    //    }

    //    //对启动器编排顺序
    //    var _appStartupsOrderBy = _startups.OrderBy(w => w.Order).ToList();
    //    _startups.Clear();
    //    _startups.AddRange(_appStartupsOrderBy);
    //}

    #endregion
}